package basic.jvm;

import java.lang.ref.PhantomReference;
import java.lang.ref.WeakReference;

/**
 * @author Cheng Jun
 * Description: 测试 Object中的 finalize()
 * https://blog.csdn.net/Jin_Kwok/article/details/81507231
 * @version 1.0
 * @date 2022/8/18 9:32
 *
 */
public class FinalizeEscapeGC {
    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes,i am still alive:)");
    }

    /**
     * Called by the garbage collector on an object when garbage collection
     * determines that there are no more references to the object.
     *
     * The general contract of finalize is that it is invoked
     * if and when the Java virtual  machine has determined that there is no longer
     * any means by which this object can be accessed by any thread that has not yet died
     *
     * The finalize method is never invoked more than once by a Java virtual machine for any given object.
     *
     * @see WeakReference
     * @see PhantomReference
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();
        // 对象第一次成功拯救自己
        SAVE_HOOK = null;
        System.gc();
        // 因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead:(");
        }
        // 下面这段代码与上面的完全相同,但是这次自救却失败了
        SAVE_HOOK = null;
        System.gc();
        // 因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no,i am dead:(");
        }
    }
}
// SAVE_HOOK对象的finalize()方法确实被GC收集器触发过，并且在被收集前成功逃脱了。
// 另外一个值得注意的地方是，代码中有两段完全一样的代码片段，执行结果却是一次逃脱成功，一次失败，
// 这是因为任何一个对象的finalize()方法都只会被系统自动调用一次，如果对象面临下一次回收，它的finalize()方法不会被再次执行，
// 因此第二段代码的自救行动失败了。因为finalize()方法已经被虚拟机调用过，虚拟机都视为“没有必要执行”(即意味着直接回收)。
// 运行结果:
//
//         finalize mehtod executed!
//         yes,i am still alive:)
//         no,i am dead:(
